import Java from "frida-java-bridge";
import { Logger } from "./log.js";

const TAG = "Bypass";

const ROOT_BIN_LIST = [
  "su",
  "busybox",
  "supersu",
  "Superuser.apk",
  "KingoUser.apk",
  "SuperSu.apk",
  "daemonsu",
];

const ROOT_PATH_LIST = [
  "/system/app/Superuser.apk",
  "/system/xbin/daemonsu",
  "/system/etc/init.d/99SuperSUDaemon",
  "/system/bin/.ext/.su",
  "/system/etc/.has_su_daemon",
  "/system/etc/.installed_su_daemon",
  "/dev/com.koushikdutta.superuser.daemon/",
];

export const Bypass = {
  /**
   *   绕过退出程序
   *   - java.lang.System.exit(I)V
   *   - Process.killProcess(Process.myPid());
   */
  exit() {
    Java.perform(() => {
      const sysexit = Java.use("java.lang.System");
      sysexit.exit.overload("int").implementation = function (args: Int64) {
        Logger.i(TAG, "[Exit][java.lang.System.exit(I)V] 避免退出应用");
      };

      // Process.killProcess(Process.myPid());
      // 防止杀死进程
      const process = Java.use("android.os.Process");
      process.killProcess.implementation = function (args: Int64) {
        Logger.i(
          TAG,
          "[Exit][android.os.Process.killProcess(I)V] 避免退出应用",
        );
      };
    });
  },

  /**
   * Root 检测
   */
  root(): any {
    if (!Java.available) {
      return;
    }
    Java.perform(() => {
      const javaFile = Java.use("java.io.File");
      javaFile.exists.implementation = function () {
        const path = this.getAbsolutePath();
        const name = this.getName();

        if (
          ROOT_BIN_LIST.indexOf(name) == -1 &&
          ROOT_PATH_LIST.indexOf(path) == -1
        ) {
          console.log(path + "-" + name);
          return this.exists.call(this); // call the original method
        }

        Logger.i(
          TAG,
          `[Bypass][Root][java.io.File.exists()] 应用尝试查找: ${path}`,
        );
        return false;
      };
    });
  },

  /**
   * frida 检测
   */
  frida() {
    const libc = Process.getModuleByName("libc.so");
    var fgetsPtr = libc.getExportByName("fgets");
    if (fgetsPtr == null) {
      Logger.w(TAG, "[Bypass][Frida] libc.so 找不到导出函数 fgets");
      return;
    }
    var fgets = new NativeFunction(fgetsPtr, "pointer", [
      "pointer",
      "int",
      "pointer",
    ]);
    var flag = true;

    Interceptor.replace(
      fgetsPtr,
      new NativeCallback(
        function (buffer, size, fp) {
          var retval = fgets(buffer, size, fp);
          var bufstr = buffer.readUtf8String();

          if (bufstr == null) {
            return retval;
          }

          // 检测 frida
          // NOTE 有可能是一个循环，导致日志非常多
          if (bufstr.indexOf("frida") > -1) {
            if (flag) {
              // Logger.i(TAG, "[Frida] 应用尝试查找:" + bufstr);
              flag = false;
            }
            buffer.writeUtf8String("ByeBye:\t0");
          }

          // TODO: tracer
          // https://github.com/r0ysue/r0tracer
          // ByPassTracerPid
          // if (bufstr.indexOf("TracerPid:") > -1) {
          //   buffer.writeUtf8String(buffer, "TracerPid:\t0");
          //   console.log("tracerpid replaced: " + buffer.readUtf8String());
          // }
          return retval;
        },
        "pointer",
        ["pointer", "int", "pointer"],
      ),
    );
  },

  /**
   * https://github.com/u0pattern/Anti-EmuDetector/blob/main/script.js
   *
   * 模拟三星设备，过模拟器检测
   */
  emu_samsung_device() {
    var build = Java.use("android.os.Build");
    build.PRODUCT.value = "gracerltexx";
    build.MANUFACTURER.value = "samsung";
    build.BRAND.value = "samsung";
    build.DEVICE.value = "gracerlte";
    build.MODEL.value = "SM-N935F";
    build.HARDWARE.value = "samsungexynos8890";
    build.FINGERPRINT.value =
      "samsung/gracerltexx/gracerlte:8.0.0/R16NW/N935FXXS4BRK2:user/lease-keys";
    build.TAGS.value = "release-keys";
  },
} as const;
